package ocean.chinacraft.common.tileentity.function;

import ocean.chinacraft.common.ModBlocks;
import ocean.chinacraft.common.ModItems;
import ocean.chinacraft.common.config.ApplicationConfig;
import ocean.chinacraft.data.ModRecipeTypes;
import ocean.chinacraft.data.recipes.JadeWorkbenchRecipe;
import ocean.chinacraft.common.world.item.ModHammer;
import ocean.chinacraft.common.world.item.ModJade;
import ocean.chinacraft.common.ModTileEntity;
import ocean.chinacraft.common.util.ModUtil;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 玉石工作台Tile
 *
 * @author zhang
 * @since 2021/11/5
 */
public class JadeWorkbenchBlockTile extends TileEntity implements ITickableTileEntity, IInventory {

    private final Logger log = LogManager.getLogger();

    private static final Map<Integer, ItemStack> STACK_MAP = new HashMap<>();

    private final ItemStackHandler itemHandler = createHandler();

    private final LazyOptional<IItemHandler> handler = LazyOptional.of(() -> itemHandler);

    protected NonNullList<ItemStack> items = NonNullList.withSize(4, ItemStack.EMPTY);

    private final Item jadeOre = ModBlocks.JADE_ORE.get().getBlock().asItem();

    private final String otherItem = ApplicationConfig.OTHER_JADE.get();

    private final Item lastItem = Registry.ITEM.getOptional(new ResourceLocation(otherItem)).orElseThrow(() ->
            new IllegalArgumentException("Unknown otherItem '" + otherItem + "'"));

    private final String yan_long_other = ApplicationConfig.YAN_LONG_OTHER.get();

    private final Item yan_long = Registry.ITEM.getOptional(new ResourceLocation(yan_long_other)).orElseThrow(() ->
            new IllegalArgumentException("Unknown otherItem '" + yan_long_other + "'"));

    private ItemStackHandler createHandler() {
        return new ItemStackHandler(4) {
            @Override
            protected void onContentsChanged(int slot) {
                JadeWorkbenchBlockTile.super.setChanged();
            }

            @Override
            public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
                if (slot == 0) {
                    return stack.getItem() instanceof ModHammer;
                } else if (slot == 1) {
                    return stack.getItem() == jadeOre || stack.getItem() instanceof ModJade;
                } else if (slot == 2) {
                    return stack.getItem() instanceof ModJade ||
                            stack.getItem() == ModItems.BIG_BRONZE_SWORD.get() ||
                            stack.getItem() == lastItem;
                } else if (slot == 3) {
                    return stack.getItem() == ModItems.YAN_LONG_BIG_KNIFE.get() ||
                            stack.getItem() == yan_long;
                }
                return false;
            }

            @Override
            public int getSlotLimit(int slot) {
                if (slot == 0) {
                    return 64;
                } else if (slot == 1) {
                    return 64;
                }
                return 1;
            }

            @Nonnull
            @Override
            public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
                if (!isItemValid(slot, stack)) {
                    return stack;
                }
                return super.insertItem(slot, stack, simulate);
            }
        };
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
            return handler.cast();
        }
        return super.getCapability(cap, side);
    }

    @Override
    public void load(@Nonnull BlockState state, @Nonnull CompoundNBT nbt) {
        itemHandler.deserializeNBT(nbt.getCompound("JadeWorkBench"));
        super.load(state, nbt);
    }

    @Nonnull
    @Override
    public CompoundNBT save(@Nonnull CompoundNBT nbt) {
        nbt.put("JadeWorkBench", itemHandler.serializeNBT());
        return super.save(nbt);
    }

    public JadeWorkbenchBlockTile(TileEntityType<?> entityType) {
        super(entityType);
    }

    public JadeWorkbenchBlockTile() {
        this(ModTileEntity.JADE_WORKBENCH_BLOCK_TILE.get());
    }

    @Override
    public void tick() {
        if (level != null && !level.isClientSide()) {
            craft();
        }
    }

    @Override
    public int getContainerSize() {
        return 4;
    }

    @Override
    public boolean isEmpty() {
        return items.isEmpty();
    }

    @Override
    public ItemStack getItem(int index) {
        return items.get(index);
    }

    @Override
    public ItemStack removeItem(int index1, int index2) {
        return ItemStackHelper.removeItem(this.items, index1, index2);
    }

    @Override
    public ItemStack removeItemNoUpdate(int index) {
        return ItemStackHelper.takeItem(this.items, index);
    }

    @Override
    public void setItem(int index, ItemStack itemStack) {
        this.items.set(index, itemStack);
        if (itemStack.getCount() > this.getMaxStackSize()) {
            itemStack.setCount(this.getMaxStackSize());
        }
    }

    @Override
    public boolean stillValid(PlayerEntity player) {
        if (this.level.getBlockEntity(this.worldPosition) != this) {
            return false;
        } else {
            return player.distanceToSqr((double) this.worldPosition.getX() + 0.5D, (double) this.worldPosition.getY() + 0.5D, (double) this.worldPosition.getZ() + 0.5D) <= 64.0D;
        }
    }

    @Override
    public void clearContent() {
        items.clear();
    }

    private void craft() {
        Inventory inv = new Inventory(itemHandler.getSlots());
        for (int i = 0; i < itemHandler.getSlots(); i++) {
            ItemStack stack = itemHandler.getStackInSlot(i);
            inv.setItem(i, stack);
            if (!stack.isEmpty()) {
                items.set(i, stack);
            }
        }
        Optional<JadeWorkbenchRecipe> recipe = Optional.empty();
        if (level != null) {
            recipe = level.getRecipeManager().getRecipeFor(ModRecipeTypes.JADE_WORKBENCH_RECIPE, inv, level);
        }
        recipe.ifPresent(iRecipe -> {
            ItemStack normalItem = itemHandler.getStackInSlot(2);
            ItemStack lastItem = itemHandler.getStackInSlot(3);
            ItemStack jadeItem = itemHandler.getStackInSlot(1);
            if (normalItem.isEmpty() && jadeItem.getItem() == ModBlocks.JADE_ORE.get().asItem()) {
                Integer random = ModUtil.random();
                try {
                    //默认合成物品，没有在几率范围内，全部给铁锭
                    //但使用的是配置文件中的参数值
//                    ItemStack output = iRecipe.getResultItem();
                    ItemStack output = new ItemStack(this.lastItem);
                    ItemStack match = match(random);
                    if (!match.isEmpty()) {
                        output = match;
                    }
                    ItemStack stack = itemHandler.getStackInSlot(0);
                    stack.setDamageValue(stack.getDamageValue() + ApplicationConfig.JADEWORKBENCH_CONSUME.get());
                    itemHandler.extractItem(0, 1, false);
                    itemHandler.extractItem(1, 1, false);
                    itemHandler.insertItem(2, output, false);
                    if (stack.getDamageValue() < stack.getMaxDamage()) {
                        itemHandler.insertItem(0, stack, false);
                    }
                } catch (Exception e) {
                    log.error("请检查ChinaCraft Mod的配置文件。没有找到这个物品。");
                    log.error(e);
                }
            } else if (normalItem.getItem() == ModItems.BIG_BRONZE_SWORD.get()
                    && lastItem.isEmpty() && jadeItem.getItem() instanceof ModJade) {
                Integer random = ModUtil.random();
                //几率之外的物品
                ItemStack output = new ItemStack(yan_long);
                Integer bigSword = ApplicationConfig.YAN_LONG_BIG_KNIFE.get();
                if (random <= bigSword) {
                    output = new ItemStack(ModItems.YAN_LONG_BIG_KNIFE.get());
                    itemHandler.extractItem(2, 1, false);
                }
                itemHandler.extractItem(1, 1, false);
                itemHandler.insertItem(3, output, false);
            }
        });
    }

    public static ItemStack match(Integer random) {
        Object[] objects = STACK_MAP.keySet().toArray();
        Integer[] intArray = ModUtil.getIntArray(objects);
        Integer approximateValue = getMatchValue(random, intArray);
        if (approximateValue != null) {
            return STACK_MAP.get(approximateValue);
        }
        return ItemStack.EMPTY;
    }

    private static Integer getMatchValue(Integer num, Integer[] source) {
        for (Integer nums : source) {
            if (num <= nums) {
                return nums;
            }
        }
        return null;
    }

    static {
        Integer jade = ApplicationConfig.JADE.get();
        Integer jasper = ApplicationConfig.JASPER.get();
        Integer hibiscusJade = ApplicationConfig.HIBISCUS_JADE.get();
        Integer purpleJade = ApplicationConfig.PURPLE_JADE.get();
        STACK_MAP.put(jade, new ItemStack(ModItems.JADE.get()));
        STACK_MAP.put(jasper, new ItemStack(ModItems.JASPER.get()));
        STACK_MAP.put(hibiscusJade, new ItemStack(ModItems.HIBISCUS_JADE.get()));
        STACK_MAP.put(purpleJade, new ItemStack(ModItems.PURPLE_JADE.get()));
    }
}

